package com.ant.backstage.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.ant.backstage.dao.FileInfoMapper;
import com.ant.backstage.dao.UserInfoMapper;
import com.ant.backstage.facade.ApiReturn;
import com.ant.backstage.facade.code.ApiReturnCode;
import com.ant.backstage.facade.dto.UserDTO;
import com.ant.backstage.facade.enums.UploadFileEnum;
import com.ant.backstage.facade.exception.BackstageBusinessException;
import com.ant.backstage.facade.model.FileInfo;
import com.ant.backstage.facade.model.UserInfo;
import com.ant.backstage.facade.request.DelGiteeImgRequest;
import com.ant.backstage.facade.request.UploadFileRequest;
import com.ant.backstage.service.EnumService;
import com.ant.backstage.service.FileUploadService;
import com.ant.backstage.utils.file.FileUploadUtils;
import com.ant.backstage.utils.giteeFile.GiteeConstant;
import com.ant.backstage.utils.giteeFile.GiteeImgBedUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

@Service("fileUploadService")
public class FileUploadServiceImpl implements FileUploadService {

    private static Logger logger = LogManager.getLogger(FileUploadServiceImpl.class);

    @Resource
    UserInfoMapper userInfoMapper;
    @Resource
    FileInfoMapper fileInfoMapper;
    @Resource
    EnumService enumService;

    @Value("${gitee.upload.path}")
    private String MEMBERS_UPLOAD_PATH;


    private String UPLOAD_AVATAR_IMG_DEF_PATH = "D:\\idea-develop-project\\Project_All\\backstage_ant\\web\\src\\main\\resources\\static\\img\\";

    @Override
    public void upload(MultipartFile file, String baseDir) throws Exception {
        ApiReturn apiReturn = new ApiReturn();
        //就算什么也不传，controller层的file也不为空，但是originalFilename会为空（亲测）
        String originalFilename = file.getOriginalFilename();

        if (!Optional.ofNullable(originalFilename).isPresent()) {
            apiReturn.setCode(ApiReturnCode.UPLOAD_FILE_NULL_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.UPLOAD_FILE_NULL_ERROR.getMessage());
            throw new BackstageBusinessException(ApiReturnCode.UPLOAD_FILE_NULL_ERROR.getMessage(),ApiReturnCode.UPLOAD_FILE_NULL_ERROR.getCode());
        }
        //检测是否上传过同样的文件

        String fileLocation = null;
        if (baseDir != null) {
            //根据文件路径上传
            fileLocation = FileUploadUtils.upload(baseDir, file);
        } else {
            //根据默认配置上传文件
            fileLocation = FileUploadUtils.upload(file);
        }
        //上传成功，根据数据库记录
//        uploadEntity.setLocation(fileLocation);
//        uploadMapper.insert(uploadEntity);
        //新文件上传成功 删除旧文件
/*        if(oldEntity != null) {
            //确保新的文件保存成功后，删除原有的同名文件(实体文件 and 数据库文件)
            FileUtils.deleteFile();
        }*/
    }

    @Override
    public void download(HttpServletResponse response, String newName) {
        //数据库查相关信息
/*        QueryWrapper<UploadEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", newName);
        UploadEntity uploadEntity = uploadMapper.selectOne(queryWrapper);

        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");        //这边可以设置文件下载时的名字，我这边用的是文件原本的名字，可以根据实际场景设置
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(uploadEntity.getOldName(), "UTF-8"));
        FileUtils.writeBytes(uploadEntity.getLocation(), response.getOutputStream());

 */
    }

    @Override
    public ApiReturn uploadAvatarImg(MultipartFile[] file, UserDTO userInfoByToken) {
        ApiReturn apiReturn = new ApiReturn();
        if (!Optional.ofNullable(file).isPresent()) {
            apiReturn.setCode(ApiReturnCode.UPLOAD_FILE_NULL_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.UPLOAD_FILE_NULL_ERROR.getMessage());
            return apiReturn;
        }
        try {
            String filenPath = UPLOAD_AVATAR_IMG_DEF_PATH;
            List<String> paths = new ArrayList<>();
            for (MultipartFile multipartFile : file) {
                filenPath += userInfoByToken.getUid() + "_" + UUID.randomUUID() + ".jpg";
                BufferedOutputStream out = new BufferedOutputStream(
                        //C:\IDEA_mode_project\agriculture\src\main
                        new FileOutputStream(new File(filenPath)));//保存图片到目录下,建立保存文件的输入流
                out.write(multipartFile.getBytes());
                out.flush();
                out.close();
                paths.add(filenPath);
            }
            //修改数据库 地址
            UserInfo userInfo = new UserInfo();
            userInfo.setUid(userInfoByToken.getUid());
            userInfo.setAvatarImgUrl(filenPath);
            userInfoMapper.updateInfoByUid(userInfo);//修改用户信息
            //上传成功 返回文件地址
            Map<String, Object> map = new HashMap<>();
            map.put("imgUrls", paths);
            apiReturn.setData(map);
        } catch (FileNotFoundException e) {
            logger.error("用户头像上传失败，上传路径异常", e);
            apiReturn.setCode(ApiReturnCode.UPLOAD_FILE_PATH_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.UPLOAD_FILE_PATH_ERROR.getMessage());
            return apiReturn;
            //return "上传失败," + e.getMessage();  //文件路径错误
        } catch (IOException e) {
            logger.error("用户头像上传失败，文件IO异常", e);
            apiReturn.setCode(ApiReturnCode.HTTP_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.HTTP_ERROR.getMessage());
            return apiReturn;
            //return "上传失败," + e.getMessage();  //文件IO错误
        }
        apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        return apiReturn;
    }

    @Override
    public ApiReturn giteeUploadFile(MultipartFile file, String fileType) throws IOException {
        ApiReturn apiReturn = uploadFileGitee(file, fileType);
        return apiReturn;
    }

    @Override
    public ApiReturn delGiteeFile(DelGiteeImgRequest request) {
        ApiReturn apiReturn = new ApiReturn();
        //1、解析取得原始上传路径
        String url = request.getUrl();
        if (StringUtils.isNotEmpty(url) && !url.contains("master/")) {
            logger.info("url：" + url + " 无法解析路径！");
            apiReturn.setCode(ApiReturnCode.PARAMS_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.PARAMS_ERROR.getMessage());
            return apiReturn;
        }
        String path = url.substring(url.indexOf("master/") + 7);
        logger.info("解析取得待删除路径：" + path);
        if (!StringUtils.isEmpty(path)) {
            //2、Gitee请求：获取sha
            String shaResult = GiteeImgBedUtil.getSha(path);
            cn.hutool.json.JSONObject jsonObj = JSONUtil.parseObj(shaResult);
            if (jsonObj == null) {
                logger.info("delFile中获取sha失败！");
                apiReturn.setCode(ApiReturnCode.DEL_FILE_FAILED.getCode());
                apiReturn.setMsg(ApiReturnCode.DEL_FILE_FAILED.getMessage());
                return apiReturn;
            }
            String sha = jsonObj.getStr(GiteeConstant.RESULT_BODY_SHA);
            //3、Gitee请求：发送删除请求
            String JSONResult = GiteeImgBedUtil.deleteFile(path, sha);
            jsonObj = JSONUtil.parseObj(JSONResult);
            if (jsonObj == null || jsonObj.getObj(GiteeConstant.RESULT_BODY_COMMIT) == null) {
                logger.info("删除文件失败！");
                apiReturn.setCode(ApiReturnCode.DEL_FILE_FAILED.getCode());
                apiReturn.setMsg(ApiReturnCode.DEL_FILE_FAILED.getMessage());
                return apiReturn;
            }
        }
        logger.info("文件路径为：" + path + " 删除成功！");
        apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        return apiReturn;
    }

    @Override
    public ApiReturn giteeUploadAvatarImg(MultipartFile file, String fileType, String uid) throws IOException {
        ApiReturn apiReturn = this.uploadFileGitee(file, fileType);
        if (apiReturn.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())) {
            //修改用户userinfo记录
            UserInfo userInfo = new UserInfo();
            userInfo.setUid(uid);
            Map data = (Map) apiReturn.getData();
            userInfo.setAvatarImgUrl(String.valueOf(data.get("url")));
            userInfoMapper.updateInfoByUid(userInfo);//修改用户信息
        }
        return apiReturn;
    }

    @Override
    public ApiReturn saveFileInfo(UploadFileRequest uploadFileRequest, UserDTO userInfoByToken) {
        ApiReturn apiReturn = new ApiReturn();
        String suffix = uploadFileRequest.getFileUrl().substring(uploadFileRequest.getFileUrl().lastIndexOf(".") + 1);
        //TODO 暂时不支持xlsx  jxls导出xlsx格式一直异常 后期
        if (!suffix.equals("xls")) {
            logger.error("模板文件暂时只支持【xls】");
            this.delTemplatefile(uploadFileRequest, userInfoByToken, apiReturn);
            apiReturn.setCode(ApiReturnCode.FILE_SUFFIX_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.FILE_SUFFIX_ERROR.getMessage());
            return apiReturn;
        }
        //校验模板文件类型
        ApiReturn uploadFileEnum = enumService.getEnumList("UploadFileEnum");
        if (!Optional.ofNullable(uploadFileEnum.getData()).isPresent()) {
            logger.info("未查询到枚举值 enum={}", JSONObject.toJSONString(uploadFileEnum));
            throw  new BackstageBusinessException(ApiReturnCode.UNKNOWN_ERROR);
        }
        Map data = (Map) uploadFileEnum.getData();
        List<UploadFileEnum> enumList = (List) data.get("UploadFileEnum");
        boolean b = enumList.stream().map(UploadFileEnum::getCode).anyMatch(code -> code.equals(uploadFileRequest.getFileBusinessType()));
        if (!b) {
            logger.error("当前模板不被支持，请联系管理员");
            apiReturn.setCode(ApiReturnCode.TEMPLATE_NO_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.TEMPLATE_NO_ERROR.getMessage());
            return apiReturn;
        }

        FileInfo fileInfo = new FileInfo();
        //文件名重复校验
        Integer count = fileInfoMapper.selectByName(uploadFileRequest.getFileName());
        /*
        问题： FUNCTION backstage.count does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual
        方案：在SQL语句中 COUNT (id) count与（id）之间存在空格，去掉空格
         */
        if (count >= 1) {
            apiReturn.setCode(ApiReturnCode.FILE_NAME_REPEAT.getCode());
            apiReturn.setMsg(ApiReturnCode.FILE_NAME_REPEAT.getMessage());
            return apiReturn;
        }
        fileInfo.setFileBusinessType(uploadFileRequest.getFileBusinessType())
                .setFileCreateTime(new Date())
                .setFileDownCount(0)
                .setFileImg(uploadFileRequest.getFileImg())
                .setFileStatus(uploadFileRequest.getFileStatus())
                .setFileName(uploadFileRequest.getFileName())
                .setFileUploader(userInfoByToken.getUname())
                .setFileUrl(uploadFileRequest.getFileUrl())
                .setFileType(uploadFileRequest.getFileUrl().substring(uploadFileRequest.getFileUrl().lastIndexOf(".") + 1));
        //保存
        int insert = fileInfoMapper.insert(fileInfo);
        if (insert != 1) {
            //保存失败删除已经上传的图片和文件
            ApiReturn a = this.delTemplatefile(uploadFileRequest, userInfoByToken, apiReturn);
            if (a.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())) {
                apiReturn.setCode(ApiReturnCode.HTTP_ERROR.getCode());
                apiReturn.setMsg(ApiReturnCode.HTTP_ERROR.getMessage());
            }else {
                logger.error("模板文件保存异常 ,已上传文件删除失败 uploadFileRequest={}", JSONObject.toJSONString(uploadFileRequest));
                throw new BackstageBusinessException(ApiReturnCode.HTTP_ERROR.getMessage(), ApiReturnCode.HTTP_ERROR.getCode());
            }
            return apiReturn;
        }
        apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        return apiReturn;
    }

    public ApiReturn delTemplatefile(UploadFileRequest uploadFileRequest, UserDTO userInfoByToken, ApiReturn apiReturn) {
        //保存失败删除已经上传的图片和文件
        DelGiteeImgRequest delGiteeImgRequest = new DelGiteeImgRequest();
        delGiteeImgRequest.setUrl(uploadFileRequest.getFileUrl());
        delGiteeImgRequest.setFileType(uploadFileRequest.getFileBusinessType());
        delGiteeImgRequest.setUid(userInfoByToken.getUid());
        ApiReturn apiReturn1 = this.delGiteeFile(delGiteeImgRequest); //删模板文件
        if (apiReturn1.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode()) && Optional.ofNullable(uploadFileRequest.getFileImg()).isPresent()) {
            delGiteeImgRequest.setUrl(uploadFileRequest.getFileImg());
            ApiReturn apiReturn2 = this.delGiteeFile(delGiteeImgRequest);//删小图
            if (apiReturn2.equals(ApiReturnCode.SUCCESSFUL.getCode())) {
                apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
            }else {
                apiReturn.setApiReturnCode(ApiReturnCode.DEL_FILE_FAILED);
            }
        }
        if (apiReturn1.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode()) && !Optional.ofNullable(uploadFileRequest.getFileImg()).isPresent()) {
            apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        }
        return apiReturn;
    }


    //文件上传传
    public ApiReturn uploadFileGitee(MultipartFile file, String fileType) throws IOException {
        ApiReturn apiReturn = new ApiReturn();
        //根据文件名生成指定的请求url
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null) {
            logger.info("服务器接收文件失败！");
            apiReturn.setCode(ApiReturnCode.IMAGE_EXIST_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.IMAGE_EXIST_ERROR.getMessage());
            return apiReturn;
        }
        String path = MEMBERS_UPLOAD_PATH + fileType + "/";
        //Gitee请求：发送上传文件请求
        String JSONResult = GiteeImgBedUtil.uploadFile(path, originalFilename, file.getBytes());
        //解析响应JSON字符串
        cn.hutool.json.JSONObject jsonObj = JSONUtil.parseObj(JSONResult);
        //请求失败
        if (jsonObj == null || jsonObj.getObj(GiteeConstant.RESULT_BODY_COMMIT) == null) {
            logger.info("上传文件失败！");
            apiReturn.setCode(ApiReturnCode.IMAGE_UPLOAD_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.IMAGE_UPLOAD_ERROR.getMessage());
            return apiReturn;
        }
        //请求成功：返回下载地址
        cn.hutool.json.JSONObject content = JSONUtil.parseObj(jsonObj.getObj(GiteeConstant.RESULT_BODY_CONTENT));
        logger.info("上传成功，下载地址为：" + content.getObj(GiteeConstant.RESULT_BODY_DOWNLOAD_URL));
        apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        Map<String, Object> map = new HashMap<>();
        map.put("url", content.getObj(GiteeConstant.RESULT_BODY_DOWNLOAD_URL).toString());
        map.put("fileType", fileType);
        apiReturn.setData(map);
        return apiReturn;
    }


}


